/*******************************************************************************
  * 文件：StateMachine.c
  * 作者：djy
  * 版本：v1.0.0
  * 日期：2020.05.29
  * 说明：状态机
*******************************************************************************/
#include "StateMachine.h"
#include "DevStandby.h"
#include "TimingCtrl.h"
#include "DevError.h"

// 状态机定义
static StateMachine_ts sStateMachine;
static void StateMchine_Handler(void);

// 状态表  按照业务逻辑划分状态机
static const StateMachineOps_ts state_machine_states[] =
{
    //设备上电
    state_machine_state(eDEV_ONPOWER,       eDEV_STANDBY,       1000,   DevOnPower          ),

    //待机
    state_machine_state(eDEV_STANDBY,       eDEV_STANDBY,       0,      DevStandby          ),

    //左灶定时
    state_machine_state(eDEV_LEFT_TIMING,   eDEV_STANDBY,       0,      DevLeftTimingCtrl   ),

    //中灶定时
    state_machine_state(eDEV_MID_TIMING,    eDEV_STANDBY,       0,      DevMidTimingCtrl    ),

    //右灶定时
    state_machine_state(eDEV_RIGHT_TIMING,  eDEV_STANDBY,       0,      DevRightTimingCtrl  ),

    //故障
    state_machine_state(eDEV_ERROR,         eDEV_STANDBY,       0,      DevError            ),

    //演示
    state_machine_state(eDEV_DEMO,          eDEV_STANDBY,       1000,   DevDemo             ),
};

/*******************************************************************************
  * 函数名  ：GetStateOps
  * 功  能  ：获取状态机操作
  * 参  数  ：DevState_te：状态机
  * 返回值  ：StateMachineOps_ts：状态机对应的Ops
  * 说  明  ：无
*******************************************************************************/
static const StateMachineOps_ts *GetStateOps(DevState_te state)
{
    U8 i;

    for (i = 0; i < ARRAY_SIZE(state_machine_states); i++)
    {
        if (state_machine_states[i].State == state)
            return &state_machine_states[i];
    }
    return NULL;
}

/*******************************************************************************
  * 函数名  ：StateMchine_ChangeLastState
  * 功  能  ：状态机状态切换为上一次状态
  * 参  数  ：无
  * 返回值  ：无
  * 说  明  ：无
*******************************************************************************/
void StateMchine_ChangeLastState(void)
{
    StateMachine_ts *sm = &sStateMachine;
    StateMachine_Change(sm->LastState);
}

/*******************************************************************************
  * 函数名  ：StateMachine_Change
  * 功  能  ：状态机状态改变
  * 参  数  ：DevState_te：将要改变的状态
  * 返回值  ：无
  * 说  明  ：无
*******************************************************************************/
void StateMachine_Change(DevState_te state)
{
    const StateMachineOps_ts *op = GetStateOps(state);

    if (op)
    {
        StateMachine_ts *sm = &sStateMachine;

#ifdef STATE_MACHINE_DEBUG
        Debug("SM: change state to %s\r\n", op->Name);
#endif
        sm->Init = 1;   //初次运行
        if (sm->CurState != state)
        {   
            //状态机切换
            sm->LastState = sm->CurState; 
            sm->CurState  = state;
            sm->TryCnt    = 0;
            sm->Op        = op;
        }
        OS_TaskAdd(StateMchine_Handler); //启动状态机任务
    }
}

/*******************************************************************************
  * 函数名  ：StateMachine_Recover
  * 功  能  ：状态机状态恢复
  * 参  数  ：DevState_te：将要恢复回的状态
  * 返回值  ：无
  * 说  明  ：仅恢复状态，不执行状态机op0和op1回调函数。与StateMachine_Change不同
*******************************************************************************/
void StateMachine_Recover(DevState_te state)
{
    const StateMachineOps_ts *op = GetStateOps(state);

    if (op)
    {
        StateMachine_ts *sm = &sStateMachine;

#ifdef STATE_MACHINE_DEBUG
        Debug("SM: recover state to %s\r\n", op->Name);
#endif
        //状态机恢复
        sm->Init = 1;
        sm->LastState = sm->CurState; 
        sm->CurState  = state;
        sm->TryCnt    = 0;
        sm->Op        = op;
    }
}

/*******************************************************************************
  * 函数名  ：StateMachine_TimerCb
  * 功  能  ：状态机定时回调
  * 参  数  ：无
  * 返回值  ：无
  * 说  明  ：为了某些状态下Op0定时切换至Op1
*******************************************************************************/
static void StateMachine_TimerCb(void)
{	
  
#ifdef STATE_MACHINE_DEBUG
	const char *name = StateMachine_GetCurStateName();
	Debug("SM: %s state Timing do op1\r\n",name);
#endif
    
    OS_TaskAdd(StateMchine_Handler);//定时创建状态机任务
	OS_TimerStop(&(sStateMachine.sSMTimer));
}

/*******************************************************************************
  * 函数名  ：StateMchine_Handler
  * 功  能  ：状态机执行函数
  * 参  数  ：无
  * 返回值  ：无
  * 说  明  ：状态机Op执行函数
*******************************************************************************/
void StateMchine_Handler(void)
{
    int ret;
    StateMachine_ts *sm = &sStateMachine;

redo:
    if (sm->Init)
    {
        //初次运行
        sm->Init = 0;
        ret = sm->Op->Op0((U32)sm);//执行初次运行回调函数
        if (sm->Op->Wait == 0)
        {
            //Op0运行完成且Op1无需等待
            goto redo;
        }
        //定时切换至Op1
        OS_TimerRestart(&(sStateMachine.sSMTimer),
                      sm->Op->Wait,
                      StateMachine_TimerCb);
    }
    else
    {
        //非初次运行
        ret = sm->Op->Op1((U32)sm);
    }

    switch (ret)
    {
        case STATE_CTRL_INIT:
            break;
        case STATE_CTRL_NEXT:
            OS_TimerStop(&(sStateMachine.sSMTimer));
            StateMachine_Change(sm->Op->NextState);
            break;
        case STATE_CTRL_WAIT:
            break;
        case STATE_CTRL_RETRY:
            sm->TryCnt++;
            StateMachine_Change(sm->Op->State);
            break;
        case STATE_CTRL_RUN:
            OS_TaskAdd(StateMchine_Handler);
            break;
    }
}

/*******************************************************************************
  * 函数名  ：StateMachine_GetCurState
  * 功  能  ：获取当前状态名称
  * 参  数  ：无
  * 返回值  ：DevState_te：当前状态
  * 说  明  ：无
*******************************************************************************/
DevState_te StateMachine_GetCurState(void)
{
	return (DevState_te)sStateMachine.CurState;
}

/*******************************************************************************
  * 函数名  ：StateMachine_GetLastState
  * 功  能  ：获取上次状态名称
  * 参  数  ：无
  * 返回值  ：DevState_te：当前状态
  * 说  明  ：无
*******************************************************************************/
DevState_te StateMachine_GetLastState(void)
{
	return (DevState_te)sStateMachine.LastState;
}

/*******************************************************************************
  * 函数名  ：StateMachine_GetCurStateName
  * 功  能  ：获取当前状态名称
  * 参  数  ：无
  * 返回值  ：const char*：当前状态的名称（字符串）
  * 说  明  ：调试打印
*******************************************************************************/
const char* StateMachine_GetCurStateName(void)
{
	return sStateMachine.Op->Name;
}

/*******************************************************************************
  * 函数名  ：StateMchine_Init
  * 功  能  ：状态机初始化
  * 参  数  ：无
  * 返回值  ：无
  * 说  明  ：上电初始化时调用，从开机上电eDEV_ONPOWER状态开始
*******************************************************************************/
void StateMchine_Init(void)
{
	StateMachine_Change(eDEV_ONPOWER);//初始状态：设备上电
}



